package com.atguigu.gmall.payment.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.model.enums.PaymentType;
import com.atguigu.gmall.model.payment.PaymentInfo;
import com.atguigu.gmall.payment.config.AlipayConfig;
import com.atguigu.gmall.payment.service.AlipayService;
import com.atguigu.gmall.payment.service.PaymentService;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Author atguigu-mqx
 * @Description TODO
 * @Date 2023/5/27 15:30
 * @Version 1.0
 */
@RestController
@RequestMapping("/api/payment/alipay")
public class AlipayApiController {

    //  http://api.gmall.com/api/payment/alipay/submit/46

    @Autowired
    private AlipayService alipayService;

    @Autowired
    private PaymentService paymentService;

    @Value("${app_id}")
    private String app_id;

    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/submit/{orderId}")
    public String submitPay(@PathVariable Long orderId){
        //  调用服务层方法。
        String form = null;
        try {
            form = alipayService.createPay(orderId);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        //  返回表单数据
        return form;
    }
    //  同步回调：
    //  http://api.gmall.com/api/payment/alipay/callback/return?charset=utf-8&out_trade_no=ATGUIGU1685174104715570&method=alipay.trade.page.pay.return&total_amount=0.01&sign=P6yxTLzCxTR8vmqsfLXQf8ldyQnJYN18fRl9WtzHe92t%2FdbZf6gVFTOF2zFpzPnJ5%2FtIDhF6xTAyhf%2FT7p4As4z9UQ8hbDAlXggWhYf7K5UbNdg7VbapuV6XRc%2FrGJHTxCNHgbcX%2FYKCflxaLRtwZrOkGMxxie3ASFzcp%2BotunIxuI7KZg4no%2BETr%2BMuB7dilWz0jhE2VAga%2BzrzCh9aRT9YXtpVSflY%2BKit0%2BSy%2FADY3EK8R8WuLSgGJ1OWgT07i9k2OZXrJkCrDG38McTbBE33wydsch%2FFp13uD4QOq%2BjSo%2BUL2llPIwWs1%2B4u5MOMeddAlaivMTwSj7pdr7U%2FvA%3D%3D&trade_no=2023052722001456601443837140&auth_app_id=2021001163617452&version=1.0&app_id=2021001163617452&sign_type=RSA2&seller_id=2088831489324244&timestamp=2023-05-27+15%3A55%3A38
    @GetMapping("/callback/return")
    public void callbackReturn(@RequestParam HashMap<String,Object> map, HttpServletResponse response) throws IOException {
        //  需要在这个方法中获取到参数; 通过参数进行校验等。
        System.out.println("map:\t"+map);
        //  返回一个地址，给web-all 使用！
        //  return_order_url: http://payment.gmall.com/pay/success.html
        response.sendRedirect(AlipayConfig.return_order_url);
//        return "redirect:"+AlipayConfig.return_order_url;
    }

    //  notify_payment_url: http://3h444s.natappfree.cc/api/payment/alipay/callback/notify
    //  https: //商家网站通知地址?voucher_detail_list=[{"amount":"0.20","merchantContribute":"0.00","name":"5折券","otherContribute":"0.20","type":"ALIPAY_DISCOUNT_VOUCHER","voucherId":"2016101200073002586200003BQ4"}]&fund_bill_list=[{"amount":"0.80","fundChannel":"ALIPAYACCOUNT"},{"amount":"0.20","fundChannel":"MDISCOUNT"}]&subject=PC网站支付交易&trade_no=2016101221001004580200203978&gmt_create=2016-10-12 21:36:12&notify_type=trade_status_sync&total_amount=1.00&out_trade_no=mobile_rdm862016-10-12213600&invoice_amount=0.80&seller_id=2088201909970555&notify_time=2016-10-12 21:41:23&trade_status=TRADE_SUCCESS&gmt_payment=2016-10-12 21:37:19&receipt_amount=0.80&passback_params=passback_params123&buyer_id=2088102114562585&app_id=2016092101248425&notify_id=7676a2e1e4e737cff30015c4b7b55e3kh6& sign_type=RSA2&buyer_pay_amount=0.80&sign=***&point_amount=0.00
    @PostMapping("/callback/notify")
    public String callbackNotify(@RequestParam HashMap<String,String> paramsMap){
        //  初步验签结果：
        boolean signVerified = false; //调用SDK验证签名
        try {
            signVerified = AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        if(signVerified){
            // TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure
            String outTradeNo = paramsMap.get("out_trade_no");
            String totalAmount = paramsMap.get("total_amount");
            String appId = paramsMap.get("app_id");
            String tradeStatus = paramsMap.get("trade_status");
            String notifyId = paramsMap.get("notify_id");
            //  根据outTradeNo查询PaymentInfo 交易记录.
            PaymentInfo paymentInfoQuery = paymentService.getPaymentInfo(outTradeNo, PaymentType.ALIPAY.name());
            //  支付宝针对同一条异步通知重试时，异步通知参数中的 notify_id 是不变的。
            //  判断 BigDecimal 如何防止精度损失, 在传递数据的时候都是以字符串的形式传递，就能够避免精度损失
            if (null == paymentInfoQuery || new BigDecimal("0.01").compareTo(new BigDecimal(totalAmount))!=0
            || !app_id.equals(appId)){
                //  返回错误结果
                return "failure";
            }
            //  判断这个消息是否属于重复发送! 过期时间： 4m、10m、10m、1h、2h、6h、15h。
            Boolean result = this.redisTemplate.opsForValue().setIfAbsent(notifyId, notifyId, 24*60+24, TimeUnit.MINUTES);
            //  result = true; 第一次消费消息. 如果为false 表示不是第一次消费.
            if (!result){
                //  返回错误结果
                return "failure";
            }

            try {
                //  判断
                if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)){
                    //  修改交易记录状态. trade_no payment_status callback_time callback_content
                    paymentService.updatePaymentStatus(outTradeNo,PaymentType.ALIPAY.name(),paramsMap);
                    //  返回正确结果
                    return "success";
                }
            } catch (Exception e) {
                //  如果有异常，需要删除缓存的key。
                this.redisTemplate.delete(notifyId);
                throw new RuntimeException(e);
            }
        }else{
            // TODO 验签失败则记录异常日志，并在response中返回failure.
            //  返回错误结果
            return "failure";
        }
        //  默认返回
        return "failure";
    }

    //  退款接口
    @GetMapping("/refund/{orderId}")
    public Result refund(@PathVariable Long orderId){
        //  获取退款方法
        Boolean flag = this.alipayService.refund(orderId);
        return Result.ok(flag);
    }

    //  关闭支付宝交易记录的控制器.
    @GetMapping("/closePay/{orderId}")
    public Boolean closePay(@PathVariable Long orderId){
        //  调用服务层方法
        Boolean flag = this.alipayService.closePay(orderId);
        return flag;
    }

    /**
     * 根据订单Id 查看是否有交易记录--是否扫码！
     * @param orderId
     * @return
     */
    @GetMapping("checkPayment/{orderId}")
    public Boolean checkPayment(@PathVariable Long orderId){
        //  调用服务层方法
        Boolean flag = this.alipayService.checkPayment(orderId);
        return flag;
    }

    /**
     * 查看是否有本地交易记录 为什么这里可以直接当参数直接传递进去！
     * @param outTradeNo
     * @return
     */
    @GetMapping("/getPaymentInfo/{outTradeNo}")
    public PaymentInfo getPaymentInfo(@PathVariable String outTradeNo){
        //  查询paymentInfo 信息。
        return this.paymentService.getPaymentInfo(outTradeNo,PaymentType.ALIPAY.name());
    }
}
